/*
File.h
*/

#ifndef File_h
#define File_h

#include <string>
#include <vector>
#include <ctime>

#include "Settings.h"
#include "Cache.h"
#include "DataBlock.h"

class FileSystem;

using namespace std;

typedef struct{
    unsigned int free0_file1_dir2; //gets padded to 4 bytes, so no sense making it a char
    unsigned int link_count; //changed in Directory::AddEntry() and RemoveEntry()
    unsigned int size;
    unsigned int num_blocks;
    unsigned int last_mod_ts; //set when file or directory is first created, and whenever the file's Write() method is called
    unsigned int ptrs_dir[Settings::InodeNumDirPtrs]; //each direct ptr is the index of a data_block
    unsigned int ptrs_indir1[Settings::InodeNumIndir1Ptrs]; //each singly-indirect ptr is an index of a block containing BlockSize/4 pointers, which then point to data blocks
    unsigned int ptrs_indir2[Settings::InodeNumIndir2Ptrs]; //each doubly-indirect ptr is an index of a block containing BlockSize/4 pointers, which then point to blocks containing BlockSize/4 pointers, which point to data_blocks
} Inode;

class File{
    friend class Directory;
    friend class FileSystem;

    public:
        File(FileSystem * fs_loc, unsigned int inode_id_loc); //need access to the FileSystem to call cache methods and write to the actual file
        unsigned int Read(unsigned int size, char * buf);
        unsigned int Write(unsigned int size, char * buf);
        int Seek(unsigned int file_offset);
        int FinalUnlink(); //called when the last reference is unlinked
    private:
        void set_inode(unsigned int new_inode_id); //sets the inode_id, inode pointer, and fills data_block_ids
        void get_num_ptrs(unsigned int * num_d_ptrs, unsigned int * num_id1_ptrs, unsigned int * num_id2_ptrs); //sets the arguments to the number of direct, singly-indirect, and doubly-indirect pointers used to access all of the blocks (based on inodes->num_blocks)
        int new_data_block(unsigned int data_block_id);//called when the file is stored in another data block

        FileSystem * fs;
        vector <unsigned int> data_block_ids;
        Inode * inode;
        unsigned int inode_id;
        unsigned int fd;

        //The file pointer is described by a data block id and an byte offset in the data block.
        unsigned int cur_file_byte;
        unsigned int cur_block_id;
        unsigned int cur_block_byte; //the next byte in the current block that will be written, when this equals Settings::BlockSize, our next write will get a new data block
};

#endif
